package org.gcoat.sequence;

import org.gcoat.analysis.GCLogHandler;
import org.gcoat.list.ArrayIntList;
import org.gcoat.list.IntList;
import org.gcoat.list.LongList;
import org.gcoat.list.SpineLongList;

public class DefaultGCTimeSequence implements GCTimeSequence, GCLogHandler {
	private final LongList times_;
	private final IntList lines_;

	public DefaultGCTimeSequence() {
		this(0, 0);
	}

	public DefaultGCTimeSequence(int runningTime, int stoppedTime) {
		times_ = new SpineLongList();
		lines_ = new ArrayIntList();
		times_.add(runningTime);
		times_.add(stoppedTime);
	}

	@Override
	public int size() {
		return size0();
	}

	private int size0() {
		return times_.size() - 2;
	}

	void rangeCheck(int i) {
		int s = size0();
		if (i < 0 || i >= s) {
			throw new IndexOutOfBoundsException("Index: " + i + "; Size: " + s);
		}
	}

	@Override
	public int getMode(int i) {
		return i & 1;
	}

	@Override
	public long getTime(int i) {
		rangeCheck(i);
		return times_.get(i + 2) - times_.get(i);
	}

	@Override
	public long getAccumulatedTime(int i) {
		rangeCheck(i);
		return times_.get(i + 2);
	}

	@Override
	public long getTotalAccumulatedTime(int i) {
		rangeCheck(i);
		return times_.get(i + 2) + times_.get(i + 1);
	}

	@Override
	public int getLineNumber(int i) {
		return lines_.get(i);
	}

	@Override
	public void append(int mode, long durationInNanos, int lineNumber) {
		if ((size0() & 1) != (mode & 1)) {
			times_.add(times_.get(times_.size() - 2));
			lines_.add(0);
		}
		times_.add(durationInNanos + times_.get(times_.size() - 2));
		lines_.add(lineNumber);
	}

}
